use std::cmp::Ordering;
use std::cmp::Ordering::{Equal, Greater, Less};
use std::fmt::{Debug, Display, Formatter};
use std::ops;

#[derive(Copy, Eq, PartialEq, Hash)]
pub struct Fraction {
    den: i32,
    //被除数,分母
    dor: i32,//除数,分子
}

impl Fraction {
    pub fn new(den: i32, dor: i32) -> Fraction {
        let d1 = den.abs();
        let d2 = dor.abs();
        //一律让负号出现在分母上

        match (dor * den).cmp(&0) {
            Less => {
                let gcd = Self::gcd(d1, d2);
                Fraction {
                    den: -d1 / gcd,
                    dor: d2 / gcd,
                }
            }
            Equal => {
                if dor != 0 {
                    Fraction {
                        den: 0,
                        dor: 1,
                    }
                } else { panic!("分母不能为零") }
            }
            Greater => {
                let gcd = Self::gcd(d1, d2);
                Fraction {
                    den: d1 / gcd,
                    dor: d2 / gcd,
                }
            }
        }
    }
    //递归计算分子和分母的最大公约数
    fn gcd(a: i32, b: i32) -> i32 {
        if b == 0 { return a; }
        if a > b { Self::gcd(b, a % b) } else { Self::gcd(a, b % a) }
    }

    /*
    分数加减乘除 函数式
    */
    fn add(self: Fraction, f: Fraction) -> Fraction {
        Self::new(self.den * f.dor + f.den * self.dor, self.dor * f.dor)
    }
    fn sub(self: Fraction, f: Fraction) -> Fraction {
        self.add(f.negation())
    }
    fn mul(self: Fraction, f: Fraction) -> Fraction {
        Self::new(self.den * f.den, self.dor * f.dor)
    }
    fn div(self: Fraction, f: Fraction) -> Fraction {
        self.mul(f.reciprocal())
    }
    //取反运算
    fn negation(self: Fraction) -> Fraction {
        Fraction {
            den: -self.den,
            dor: self.dor,
        }
    }
    //取倒数运算
    fn reciprocal(self: Fraction) -> Fraction {
        Fraction {
            den: self.dor,
            dor: self.den,
        }
    }
    pub fn to_int(self: Fraction) -> Option<i32> {
        if let Equal = self.dor.cmp(&1) {
            Some(self.den)
        } else {
            None
        }
    }
}


impl Display for Fraction {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "({},{})", self.den, self.dor)
    }
}

//把整数类型转换为分数的trait
pub trait ToFraction {
    fn f(self) -> Fraction;
}

impl ToFraction for i32 {
    fn f(self) -> Fraction {
        Fraction {
            den: self,
            dor: 1,
        }
    }
}

impl Debug for Fraction {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "({},{})", self.den, self.dor)
    }
}

impl ToFraction for (i32, i32)
{
    fn f(self) -> Fraction {
        Fraction::new(self.0, self.1)
    }
}

impl Clone for Fraction {
    fn clone(&self) -> Self {
        *self
    }
}
/*
加减乘除福符号运算
*/
impl ops::Add for Fraction {
    type Output = Fraction;
    fn add(self, rhs: Self) -> Self::Output {
        Self::add(self, rhs)
    }
}

impl ops::Sub for Fraction {
    type Output = Fraction;
    fn sub(self, rhs: Self) -> Self::Output {
        Self::sub(self, rhs)
    }
}

impl ops::Mul for Fraction {
    type Output = Fraction;
    fn mul(self, rhs: Self) -> Self::Output {
        Self::mul(self, rhs)
    }
}

impl ops::Div for Fraction {
    type Output = Fraction;
    fn div(self, rhs: Self) -> Self::Output {
        Self::div(self, rhs)
    }
}

impl PartialOrd for Fraction {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let res = self.sub(*other).den;
        match res.cmp(&0) {
            Less => { Some(Less) }
            Equal => { Some(Equal) }
            Greater => { Some(Greater) }
        }
    }

    fn lt(&self, other: &Self) -> bool {
        matches!(self.partial_cmp(other), Some(Less))
    }

    fn le(&self, other: &Self) -> bool {
        matches!(self.partial_cmp(other), Some(Less | Equal))
    }

    fn gt(&self, other: &Self) -> bool {
        matches!(self.partial_cmp(other), Some(Greater))
    }

    fn ge(&self, other: &Self) -> bool {
        matches!(self.partial_cmp(other), Some(Greater| Equal))
    }
}